import { _decorator, Component, Node, Sprite, v3, Size } from 'cc';
import { GlobalConfig } from '../../Init/Config/GlobalConfig';
import { GlobalEnum } from '../../Init/Config/GlobalEnum';
import { GlobalTmpData } from '../../Init/Config/GlobalTmpData';
import EventManager from '../../Init/Managers/EventManager';
import { EventTypes } from '../../Init/Managers/EventTypes';
import GlobalPool from '../../Init/Tools/GlobalPool';
import { Zombie2D } from './Zombie2D';
const { ccclass, property } = _decorator;
//2D
@ccclass('BasicEnemy')
export class BasicEnemy {
    node: Node;
    enemyType = GlobalEnum.EnemyTypes.Army; //需要子类覆盖
    state = GlobalEnum.EnemyState.Alive;
    //当前可以被僵尸瞄准攻击的次数-由血量决定
    aimNum = 1;
    hp = 1;
    maxHp = 1;
    isBoss = false;
    isStatic = false;

    mappingProps = {
        enemyType: null,
        enemyName: null,
        node: null,
        state: null,
    }
    constructor(n: Node) {
        this.node = n;
        // this.node[GlobalEnum.ExtralProp.customProps] = { hp: this.hp, maxHp: this.hp };
        let sp = this.node.getComponent(Sprite);
        if (sp) {
            sp.enabled = GlobalConfig.isShow2dCollider;
        }
    }
    init(d?) {
        this.node[GlobalEnum.ExtralProp.customProps] = { hp: this.hp, maxHp: this.hp };
        this.mappingProps.enemyType = this.enemyType;
        this.mappingProps.node = this.node;
        this.aimNum = this.hp;
        this.updateProps();
        this.setStateData();
    }

    setHp(hp) {
        this.hp = hp;
        this.aimNum = hp;
        this.maxHp = hp;
        this.node[GlobalEnum.ExtralProp.customProps].hp = hp;
        this.node[GlobalEnum.ExtralProp.customProps].maxHp = hp;
    }

    setBodySize(s: Size) {

    }

    reset() {
        this.resetState();
    }

    update(dt) {
        this.updateState(dt);
    }

    //#region -----------计算方法---------
    updateProps() {
        this.mappingProps.enemyType = this.enemyType;
        this.mappingProps.state = this.state;
    }
    /**被瞄准攻击 */
    aimByZombie() {
        this.aimNum--;
        this.aimNum = this.aimNum < 0 ? 0 : this.aimNum;
    }

    /**被击中 */
    byAtk(isChange = false, cb?) {
        if (this.hp <= 0) return;
        this.hp--;

        this.node[GlobalEnum.ExtralProp.customProps].hp = this.hp;
        if (this.hp <= 0) {
            this.hp = 0;
            this.changeState(GlobalEnum.EnemyState.Death, { isChange: isChange, finishCb: cb });
        }
    }
    //#endregion

    //#region ------------行为状态控制-------
    protected _stateRecs: { [state: number]: EnemyState } = {};
    public _curState: GlobalEnum.EnemyState = null;

    /**设置初始状态 */
    protected setStateData() {
        this._stateRecs[GlobalEnum.EnemyState.Alive] = new EnemyAlive(this);
        this._stateRecs[GlobalEnum.EnemyState.Death] = new EnemyDeath(this);

        setTimeout(() => {
            this.changeState(GlobalEnum.EnemyState.Alive);
        }, 0);
    }
    /**重置状态 */
    protected resetState() {
        for (const key in this._stateRecs) {
            this._stateRecs[key].offEvents();
        }
        this._stateRecs = {};
        this._curState = null;
    }
    /**
    * 切换状态
    * @param state 
    * @param enterData 传入参数
    * @param isForth 是否强制切换
    * @returns 
    */
    public changeState(state: GlobalEnum.EnemyState, enterData?, isForth = false) {
        if (this._curState === state && !isForth) return;
        //退出之前的状态
        if (this._stateRecs[this._curState]) {
            this._stateRecs[this._curState].exit();
        }
        //切换到新的状态
        if (this._stateRecs[state]) {
            this._curState = state;
            this._stateRecs[this._curState].enter(enterData);
        }
        this.mappingProps.state = this._curState;
    }
    /**更新状态 */
    protected updateState(dt) {
        if (this._stateRecs[this._curState]) {
            this._stateRecs[this._curState].update(dt);
        }
    }
    // #endregion
}

//#region -----------敌人行为----------
export class EnemyState {
    cmp: BasicEnemy = null;
    constructor(enemy: BasicEnemy) {
        this.cmp = enemy;
    }

    public enter(d?) {

    }
    public onEevents() {

    }
    public offEvents() {

    }
    public update(dt) {

    }
    public exit() {

    }
}
//存活
export class EnemyAlive extends EnemyState {
    public isInArea = false;
    public atk = 1;
    // 攻击频率
    public atkCd = 1;
    public atkTime = 0;
    public atkDist = 100;
    // 检测频率控制
    public checkCd = 0.1;
    public checkTime = 0;
    //检测信息
    public _outRes = { wp: v3(), r: 0, outZombie: null }
    //发射信息
    public _shootRes = { t: 0, p: v3(), direc: v3(), h: 0.8, atk: 1 };

    public enter(d?): void {
        this.isInArea = false;
        this.atkTime = 0;
        this.checkTime = 0;
        this._outRes.r = this.atkDist;
        this._outRes.outZombie = null;
        this._shootRes.atk = this.atk;
    }

    public update(dt: any): void {
        this.checkZombies(dt);
        this.checkAtk(dt);
    }

    //检测僵尸
    public checkZombies(dt) {
        this.checkTime += dt;
        if (this.checkTime >= this.checkCd) {
            this.checkTime = 0;
            //检测信息
            this._outRes.wp.set(this.cmp.node.worldPosition);
            this._outRes.outZombie = null;
            this._outRes.r = this.atkDist;
            EventManager.emit(EventTypes.EnemyEvents.CheckClosetZombie, this._outRes);
            this.isInArea = !!this._outRes.outZombie;
            if (this.isInArea) {
                this.onChecked(this._outRes.outZombie);
            }
        }
    }
    /**检测到之后 */
    public onChecked(zombie?: Zombie2D) {
        //发射信息    
        this._shootRes.p.set(this.cmp.node.position);
        this._shootRes.direc.set(zombie.node.worldPosition).subtract(this.cmp.node.worldPosition);
    }

    //攻击频率
    public checkAtk(dt) {
        if (!this.isInArea) return;
        this.atkTime += dt;
        if (this.atkTime >= this.atkCd) {
            this.atkTime = 0;
            this.onAtk();
        }
    }

    //攻击
    public onAtk() {

    }

}
//死亡
export class EnemyDeath extends EnemyState {
    delayTime = 0;
    isDeath = false;
    isChange = false;
    finishCb = null;
    deathPos = v3();
    public enter(d: { isChange: boolean, finishCb: Function }): void {
        this.isChange = d.isChange;
        this.finishCb = d.finishCb;
        this.delayTime = 0;
        this.isDeath = false;
        this.deathPos.set(this.cmp.node.position);
    }

    public update(dt: any): void {
        if (!this.isDeath) {
            this.delayTime += dt;
            if (this.delayTime >= GlobalConfig.Enemy.deathTime) {
                this.isDeath = true;
                this.onFinish();
            }
        }
    }

    protected onFinish() {
        //生成僵尸
        if (this.isChange) {
            EventManager.emit(EventTypes.RoleEvents.CreateZombie, this.deathPos);
        }

        this.finishCb && this.finishCb();
        GlobalPool.put(this.cmp.node);
    }
}
//#endregion